package com.dl.mall.service.user.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.dl.mall.config.RabbitmqConfig;
import com.dl.mall.config.alipay.AliPayConfig;
import com.dl.mall.config.alipay.AliPayProperties;
import com.dl.mall.entity.Page;
import com.dl.mall.entity.ProductSpecs;
import com.dl.mall.entity.user.Order;
import com.dl.mall.entity.user.OrderInfo;
import com.dl.mall.entity.vo.CartVo;
import com.dl.mall.entity.vo.HistoryOrderVo;
import com.dl.mall.entity.vo.OrderCartVo;
import com.dl.mall.exception.NoInventoryException;
import com.dl.mall.mapper.OrderMapper;
import com.dl.mall.service.admin.ProductService_Admin;
import com.dl.mall.service.user.OrderService;
import com.dl.mall.service.user.ProductService;
import com.dl.mall.utils.GenerateOrderId;
import com.dl.mall.utils.RedisUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author DL
 * @create 2022-04-13 14:02
 */
@Service
@Transactional
@Slf4j
public class OrderServiceImpl implements OrderService {

    private static final String CHARSET = "UTF-8";

    private static final String EXPIRE = "30m";// 交易多长时间后关闭

    @Resource
    private AliPayConfig aliPayConfig;
    @Resource
    private AliPayProperties aliPayProperties;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private ProductService productService;
    @Resource
    private ProductService_Admin productServiceAdmin;
    @Resource
    private RedisUtils redisUtils;

    /**
     * 根据 订单id和状态 更新订单
     * @param orderId 订单id
     * @param orderState 状态
     * @return 是否成功
     */
    @Override
    public boolean modifyOrderById(String orderId, Integer orderState) {
        return orderMapper.updateOrderState(orderId, orderState) != 0;
    }

    @Resource
    private RabbitTemplate rabbitTemplate;
    /**
     * 根据 用户id和订单商品 生成订单
     * 使用redis扣除库存后，直接返回订单id，双表插入通过mq进行异步处理
     * @param userId 用户id
     * @param cartVoList 订单商品信息
     * @return 订单信息
     */
    @Override
    public Order generateOrder(String userId, List<CartVo> cartVoList) throws NoInventoryException {
        //long orderId = GenerateOrderId.generate();
        String orderId = GenerateOrderId.generate();
        // 根据 订单商品信息 生成 订单信息表的信息
        List<OrderInfo> orderInfoList = cartVoList.stream()
                        .map(cartVo -> new OrderInfo().setOrderId(orderId).setSpecsId(cartVo.getSpecsId()).setTotal(cartVo.getCount()))
                        .collect(Collectors.toList());

        // 根据 订单商品信息 获得订单总金额
        BigDecimal totalAmount = cartVoList.stream()
                .map(cartVo -> cartVo.getPrice().multiply(BigDecimal.valueOf(cartVo.getCount())))
                .reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        orderInfoList.forEach(item->{
            String specsId = item.getSpecsId();// 规格id
            Integer total = item.getTotal();// 要购买的数量
            Integer stock = (Integer) redisUtils.hget("productSpecs", specsId);
            log.info("redis中查询 {} 的库存为{}，如果为null说明redis没有缓存，退化为数据库查询", specsId, stock);
            if (stock == null){ // 如果为空说明redis没有缓存，退化为数据库查询
                ProductSpecs productSpecs = productService.getProductSpecsBySpecsId(specsId);
                if (productSpecs.getSpecsStock() < total){
                    log.info("从数据库查询 {} 商品库存不足，要购买{}个，库存只有{}个", specsId, total, productSpecs.getSpecsStock());
                    throw new NoInventoryException("查询 "+ specsId +" 商品库存不足，要购买" + total + "个，库存只有" + productSpecs.getSpecsStock() +"个");
                }else {
                    boolean seckill = productService.deductSpecsStockSeckill(specsId, item.getTotal());
                    System.out.println("seckill = " + seckill);
                    if (!seckill) throw new NoInventoryException();
                    // 向redis加入订单超时间
                    boolean set = redisUtils.set("order:" + orderId, userId, 1800);
                    if (set){
                        log.info("订单创建成功！订单id为：{}", orderId);
                    }
                }
            }else {
                if (stock < total){
                    log.info("从redis查询 {} 商品库存不足，要购买{}个，库存只有{}个", specsId, total, stock);
                    throw new NoInventoryException("查询 "+ specsId +" 商品库存不足，要购买" + total + "个，库存只有" + stock +"个");
                }else {
                    // 如果库存充足直接在redis中扣除库存并返回
                    double redisStock = redisUtils.hdecr("productSpecs", item.getSpecsId(), item.getTotal());
                    log.info("购买成功，规格id：{}，购买{}个，剩余库存{}个", item.getSpecsId(), item.getTotal(), redisStock);
                    // 向redis加入订单超时间
                    boolean set = redisUtils.set("order:" + orderId, userId, 1800);
                    if (set){
                        log.info("订单创建成功！订单id为：{}", orderId);
                    }
                }
            }
        });
        Order order = new Order();// 创建订单类
        order.setOrderId(orderId).setUserId(userId).setTotalAmount(totalAmount).setOrderState(0);
        HashMap<String, Object> map = new HashMap<>();
        map.put("order",order);
        map.put("orderInfoList",orderInfoList);
        System.out.println("map = " + map);
        rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_NAME,"", map);
        return order;
    }

    /**
     * 根据 订单id 获得订单商品信息
     * @param orderId 订单id
     * @return 订单商品信息
     */
    @Override
    public List<OrderCartVo> getOrderCartVoById(String orderId) {
        return orderMapper.queryOrderCartVoById(orderId);
    }

    /**
     * 根据 订单号 查询订单信息
     * @param orderId 订单号
     * @return 订单
     */
    @Override
    public Order getOrderInfoById(String orderId) {
        return orderMapper.queryOrderInfoById(orderId);
    }

    /**
     * 根据 订单id 使用支付宝支付，返回string内容
     * @param orderId 订单号
     * @return 支付宝生成内容
     */
    @Override
    public String aliPay(String orderId, String addressId) {
        // 1.查订单信息
        Order order = orderMapper.queryOrderInfoById(orderId);

        if (order.getAddressId() == null){// 防止重复设置
            // 设置订单地址
            orderMapper.updateOrderAddress(orderId, addressId);
        }

        // 2.支付内容参数
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        // 订单号
        model.setOutTradeNo(String.valueOf(orderId));
        // 销售产品码，电脑网站固定为FAST_INSTANT_TRADE_PAY
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        // 商品金额
        model.setTotalAmount(String.valueOf(order.getTotalAmount()));
        // 商品标题
        model.setSubject("订单支付");
        // 商品描述
        model.setBody("支付宝支付，共" + order.getTotalAmount() + "元");
        // 最晚付款时间
        model.setTimeoutExpress(EXPIRE);

        // 3.发起支付请求
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

        // 3.1设置回调
        request.setReturnUrl(aliPayProperties.getReturnUrl());
        request.setNotifyUrl(aliPayProperties.getNotifyUrl());
        request.setBizModel(model);

        String body = null;
        // 3.2设置页面模型数据
        try {
            body = aliPayConfig.getAliPayClient().pageExecute(request).getBody();
            System.out.println("body = " + body);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return body;
    }

    @Override
    public List<OrderInfo> getOrderInfoListById(String orderId) {
        return orderMapper.queryOrderInfoListById(orderId);
    }


    /**
     * 根据 用户id 获得历史订单信息（订单 + 商品）
     * @param userId 用户id
     * @return 历史订单信息
     */
    @Override
    public Page<HistoryOrderVo> getHistoryOrderInfo(String userId, JSONObject jsonObject) {
/*        PageHelper.startPage(currentPage, pageSize);
        List<Product> list = productMapper.queryProductByKeyWord(keyWord);
        return (Page<Product>) PageUtils.getPage(list);*/
        JSONObject condition = jsonObject.getJSONObject("condition"); // 总条件
        JSONObject orderSate = condition.getJSONObject("orderSate"); // 要查询状态
        boolean unpaid = orderSate.getBooleanValue("unpaid");
        boolean paid = orderSate.getBooleanValue("paid");
        boolean cancel = orderSate.getBooleanValue("cancel");

        ArrayList<Integer> orderStateList = new ArrayList<>();// 状态id集合
        if (unpaid) orderStateList.add(0);
        if (paid) orderStateList.add(1);
        if (cancel) orderStateList.add(2);

        Integer currentPage = condition.getInteger("currentPage");
        PageHelper.startPage(currentPage, 10);
        Map<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        map.put("orderStateList", orderStateList);
        map.put("orderId", condition.getString("orderId"));

        System.out.println("map = " + map);

        List<HashMap<String, Object>> list = orderMapper.queryHistoryOrderInfo(map);
        System.out.println("list = " + list);
        ArrayList<HistoryOrderVo> historyOrderVoList = new ArrayList<>();
        list.forEach(item -> {
            HistoryOrderVo historyOrderVo = new HistoryOrderVo();
            historyOrderVo.setOrderId((String) item.get("order_id"));
            historyOrderVo.setTotalAmount((BigDecimal) item.get("total_amount"));
            historyOrderVo.setOrderState((Integer) item.get("order_state"));
            historyOrderVo.setCreateTime((Timestamp) item.get("create_time"));
            historyOrderVo.setUpdateTime((Timestamp) item.get("update_time"));

            String productIdStr = (String) item.get("product_id");
            String[] productArr = productIdStr.split(",");

            String specsImgStr = (String) item.get("specs_img");
            String[] specsImgArr = specsImgStr.split(",");

            String nameStr = (String) item.get("name");
            String[] nameArr = nameStr.split(",");

            String productSpecsStr = (String) item.get("product_specs");
            String[] productSpecsArr = productSpecsStr.split("-,");
            //System.out.println("productSpecsStr = " + productSpecsStr);
            //System.out.println("productSpecsArr = " + Arrays.toString(productSpecsArr));

            String priceStr = (String) item.get("price");
            String[] priceArr = priceStr.split(",");

            String totalStr = (String) item.get("total");
            String[] totalArr = totalStr.split(",");

            ArrayList<OrderCartVo> historyCartVoList = new ArrayList<>();
            for (int i = 0; i < productArr.length; i++) {
                OrderCartVo orderCartVo = new OrderCartVo();
                orderCartVo.setProductId(productArr[i]);
                orderCartVo.setSpecsImg(specsImgArr[i]);
                orderCartVo.setName(nameArr[i]);

                productSpecsArr[i] = productSpecsArr[i].replaceAll("-","");
                orderCartVo.setProductSpecs(productSpecsArr[i]);
                orderCartVo.setPrice(new BigDecimal(priceArr[i]));
                orderCartVo.setTotal(Integer.parseInt(totalArr[i]));
                historyCartVoList.add(orderCartVo);
                historyOrderVo.setHistoryCartVoList(historyCartVoList);
            }

            historyOrderVoList.add(historyOrderVo);
        });

        historyOrderVoList.forEach(System.out::println);

        PageInfo<?> pageInfo = new PageInfo<>(list);

        Page<HistoryOrderVo> page = new Page<>();//分页对象，保存分页所有信息
        page.setTotal((int) pageInfo.getTotal());//设置数据总数
        page.setPageSize(pageInfo.getPageSize());//设置页面大小
        page.setTotalPage(pageInfo.getPages());//设置页面总数
        page.setCurrentPage(pageInfo.getPageNum());//设置当前页码
        page.setList( historyOrderVoList);//放入主体信息

        return page;
    }
}
